/*
 * Copyright (c) 2018 Hitevision
 */

package tw.com.hitevision.whiteboard.android.render;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.net.Uri;
import android.util.Log;

import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy;
import com.bumptech.glide.request.FutureTarget;

import tw.com.hitevision.whiteboard.android.stateFile.ImageStateFile;
import tw.com.hitevision.whiteboard.android.stateFile.StateFileSaver;
import tw.com.hitevision.whiteboard.android.util.GlideApp;

public class Image extends BaseItem {
    private static final String TAG = Image.class.getSimpleName();
    private Bitmap bitmap;
    private final Matrix transform;
    private final RectF bounds;
    private final float extend = 10;
    private final Uri contentUri;
    private float bitmapWidth;
    private float bitmapHeight;
    private FutureTarget<Bitmap> target;
    private final String contentURL;
    private String imageFileName;

    @Deprecated
    public Image(Bitmap bitmap) {
        this.bitmap = bitmap;
        contentUri = null;
        contentURL = null;
        transform = new Matrix();
        bounds = new RectF();
        this.bitmapWidth = bitmap.getWidth();
        this.bitmapHeight = bitmap.getHeight();
        imageFileName = createImageFileName();
    }

    public Image(Uri contentUri, float bitmapWidth, float bitmapHeight) {
        this.contentUri = contentUri;
        bitmap = null;
        contentURL = null;
        transform = new Matrix();
        bounds = new RectF();
        this.bitmapWidth = bitmapWidth;
        this.bitmapHeight = bitmapHeight;
        imageFileName = createImageFileName();
    }

    public Image(String contentURL, float bitmapWidth, float bitmapHeight) {
        this.contentURL = contentURL;
        bitmap = null;
        contentUri = null;
        transform = new Matrix();
        bounds = new RectF();
        this.bitmapWidth = bitmapWidth;
        this.bitmapHeight = bitmapHeight;
        imageFileName = createImageFileName();
    }

    @Override
    public void setBounds(float x, float y, float width, float height) {
        super.setBounds(x, y, width, height);

        transform.setScale(width / bitmapWidth, height / bitmapHeight);
        transform.postTranslate(x, y);
    }

    @Override
    public void setPosition(float x, float y) {
        final float dx = x - getX();
        final float dy = y - getY();
        transform.postTranslate(dx, dy);

        super.setPosition(x, y);
    }

    @Override
    public void scaleFromPoint(float rateX, float rateY, PointF p) {
        transform.postScale(rateX, rateY, p.x, p.y);

        updateBounds();
    }

    @Override
    public void rotateFromPoint(float degree, PointF p) {
        transform.postRotate(degree, p.x, p.y);

        updateBounds();
    }

    public void updateBounds() {
        bounds.set(0, 0, bitmapWidth, bitmapHeight);
        transform.mapRect(bounds);

        x = bounds.left - extend;
        y = bounds.top - extend;
        width = bounds.right - x + extend;
        height = bounds.bottom - y + extend;

        updateRegion();
    }

    @Override
    public void moveBy(float dx, float dy) {
        super.moveBy(dx, dy);
        bounds.offset(dx, dy);

        transform.postTranslate(dx, dy);
    }

    @Override
    public BaseItem copy() {
        final Image image;
        if (contentUri != null) {
            image = new Image(Uri.parse(contentUri.toString()), bitmapWidth, bitmapHeight);
        } else if (contentURL != null) {
            image = new Image(contentURL, bitmapWidth, bitmapHeight);
        } else if (bitmap != null) {
            image = new Image(bitmap.copy(bitmap.getConfig(), false));
        } else {
            return null;
        }

        image.transform.set(transform);
        image.bounds.set(bounds);
        image.x = x;
        image.y = y;
        image.width = width;
        image.height = height;
        image.updateRegion();

        image.imageFileName = this.imageFileName;

        return image;
    }

    public static BaseItem copyFromStateFile(Context context, float x, float y, float width, float height,
                                             float bitmapWidth, float bitmapHeight,
                                             float[] transformValues, RectF bounds, String imageFileName, String contentUriStr, String contentURL) {
        final Image image;
        StateFileSaver stateFileSaver = StateFileSaver.getInstance(context);
        Bitmap bitmap = stateFileSaver.getJsonImage(imageFileName);

        if (bitmap != null) {
            log("Json: copy the image from file.");
            image = new Image(bitmap);
            image.bitmapWidth = bitmapWidth;
            image.bitmapHeight = bitmapHeight;
        } else if (contentURL != null) {
            log("Json: copy the image from Url.");
            image = new Image(contentURL, bitmapWidth, bitmapHeight);
        } else if (contentUriStr != null && contentUriStr.length() > 0) {
            log("Json: copy the image from Uri.");
            image = new Image(Uri.parse(contentUriStr), bitmapWidth, bitmapHeight);
        } else {
            return null;
        }

        image.transform.setValues(transformValues);
        image.bounds.set(bounds);
        image.x = x;
        image.y = y;
        image.width = width;
        image.height = height;
        image.updateRegion();

        image.imageFileName = imageFileName;

        return image;
    }

    private String createImageFileName() {
        return "image" + getId() + ".png";
    }

    public String getImageFileName() {
        return imageFileName;
    }

    public ImageStateFile getImageStateFile() {
        return new ImageStateFile(this, bitmapWidth, bitmapHeight, transform, bounds, imageFileName, contentUri, contentURL);
    }

    @Override
    public void render(Canvas canvas, Paint paint, Context context) {
//        log("render");
        if (bitmap != null && !bitmap.isRecycled()) {
            log("- bitmap!");
            paint.setAlpha(0xff);
            canvas.drawBitmap(bitmap, transform, paint);
        } else if (contentUri != null) {
            log("- contentUri=" + contentUri);
            try {
                target = GlideApp.with(context)
                        .asBitmap()
                        .diskCacheStrategy(DiskCacheStrategy.ALL)
                        .downsample(DownsampleStrategy.CENTER_INSIDE)
                        .load(contentUri)
                        .submit((int) bitmapWidth, (int) bitmapHeight);
                bitmap = target.get();

                paint.setAlpha(0xff);
                canvas.drawBitmap(bitmap, transform, paint);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (contentURL != null && !contentURL.isEmpty()) {
            try {
                target = GlideApp.with(context)
                        .asBitmap()
                        .diskCacheStrategy(DiskCacheStrategy.ALL)
                        .downsample(DownsampleStrategy.CENTER_INSIDE)
                        .load(contentURL)
                        .submit((int) bitmapWidth, (int) bitmapHeight);
                bitmap = target.get();

                paint.setAlpha(0xff);
                canvas.drawBitmap(bitmap, transform, paint);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void release(Context context) {
        if (target != null) {
            GlideApp.with(context).clear(target);
            bitmap = null;
        }
    }

    private static void log(String msg) {
        Log.d(TAG, msg);
    }


}
